<?php

declare(strict_types=1);

namespace App\Order\Service;

use App\Common\Constants\ErrorCode;
use App\Common\Service\BaseService;
use App\Order\Model\KzRefundLogModel;
use App\Order\Model\OrderGoodsModel;
use App\Order\Model\OrderModel;
use App\Order\Model\OrderRefundModel;
use App\Order\Model\RefundGoodsModel;
use App\Order\Model\WxRefundLogModel;
use App\Order\Repository\RepositoryFactory;
use App\User\Service\MemberService;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use ReflectionFunction;
use stdClass;
use Exception;

class ShopOrderService extends BaseService
{

    /**
     * @Inject()
     * @var MemberService
     */
    protected MemberService $memberService;

    protected $orderRepository;

    protected $refund_status_name = ['待处理','已驳回','已退款'];

    public function __construct(RepositoryFactory $repoFactory)
    {
        parent::__construct();
        $this->orderRepository = $repoFactory->getRepository("order");
    }

    /**
     * 商家订单列表
     *
     * @param $limit
     * @param $where
     * @return array
     */
    public function getList2($limit, $where)
    {
        $is_refund = false;
        $refund = [];
        $type = '';
        if ($where instanceof \Closure) {
            $arr = (new ReflectionFunction($where))->getStaticVariables();
            if (in_array($arr['status'], [5, 6])) {
                $is_refund = true;
                if ($arr['status'] == 5) {$s = 0;$h = 1;$type = 'right';}
                if ($arr['status'] == 6) {$s = 2;$h = 2;$type = 'left';}
                $refund = OrderRefundModel::query()
                    ->selectRaw('order_no as order_num,refund_no,handle_type')
                    ->where(['status' => $s, 'handle_type' => $h, 'shop_id' => $arr['shop_id']]);
            }
        }
        $result = [];
        $list = OrderModel::query()
            ->when($is_refund, function ($query) use($refund, $type){
                return $query->joinSub($refund, 'refund', 'store_order.order_no', '=', 'refund.order_num', $type)->where('refund_no','<>','');
            })
            ->where($where)->orderBy('store_order.create_at', 'desc')->paginate($limit);
        foreach ($list as $v) {
            $_data['create_at'] = $v->create_at;
            $_data['delivery_method'] = $v['deal_type'];
            $_data['delivery_method_cn'] = OrderModel::$deliveryMethodZh[$v['deal_type']];
            $_data['status'] = $v->status;
            $_data['deal_type'] = $v->deal_type;
            if ($v['deal_type'] == 1) {
                $_data['status_name'] = OrderModel::$deliveryOrderStatusNamesZh[$v['status']];
                $_data['username'] = $v->address->username;
                $_data['phone'] = $v->address->phone;
                $_data['city'] = $v->address->city;
                $_data['area'] = $v->address->area;
                $_data['address'] = $v->address->address;
            } else {
                $_data['status_name'] = OrderModel::$selfTakeOrderStatusNameZh[$v['status']];
                $_data['username'] = $v->member ? $v->member->nickname : '';
                $_data['phone'] = $v->member ? $v->member->phone : '';
                $_data['city'] = '';
                $_data['area'] = '';
                $_data['address'] = $v->shop->address;
            }
            $v->refund_no ? ($_data['refund_status_cn'] = OrderModel::$handleStatusZh[$v->handle_type]).($_data['refund_no'] = $v->refund_no):
                ($_data['refund_status_cn'] = '').($_data['refund_no'] = '');
//            if ($v->refund) {
//                $_data['refund_status_cn'] = OrderModel::$handleStatusZh[$v->refund->handle_type];
//                $_data['refund_no'] = $v->refund->refund_no;
//            }
            $_data['shop_address'] = $v->shop->address;
            $_data['order_no'] = $v->order_no;
            $_data['serial_number'] = $v['serial_num'];
            $_data['is_group_buy'] = boolval($v['order_type'] == 6);
            $_data['pay_type'] = OrderModel::$posTypesZh[$v['pay_type']];
            $_data['pos_status_cn'] = OrderModel::$posTypesZh[$v['pos_type']];
            $_data['appointment_time'] = $v['appointment_time'];
            $is_refund && $v->refund && $_data['status_name'] = $this->refund_status_name[$v->refund->status];
            $result[] = $_data;
        }
        return $this->success($result, $list->total());
    }

    /**
     * 商家订单列表
     *
     * @param $limit
     * @param $where
     * @return array
     */
    public function getList($limit, $where)
    {
        $result = [];
        $list = OrderModel::query()->where($where)->orderBy('create_at', 'desc')->paginate($limit);
        foreach ($list as $v) {
            $_data['create_at'] = $v->create_at;
            $_data['delivery_method'] = $v['deal_type'];
            $_data['delivery_method_cn'] = OrderModel::$deliveryMethodZh[$v['deal_type']];
            $_data['status'] = $v->status;
            $_data['deal_type'] = $v->deal_type;
            if ($v['deal_type'] == 1) {
                $_data['status_name'] = OrderModel::$deliveryOrderStatusNamesZh[$v['status']];
                $_data['username'] = $v->address->username;
                $_data['phone'] = $v->address->phone;
                $_data['city'] = $v->address->city;
                $_data['area'] = $v->address->area;
                $_data['address'] = $v->address->address;
            } else {
                $_data['status_name'] = OrderModel::$selfTakeOrderStatusNameZh[$v['status']];
                $_data['username'] = $v->member ? $v->member->nickname : '';
                $_data['phone'] = $v->member ? $v->member->phone : '';
                $_data['city'] = '';
                $_data['area'] = '';
                $_data['address'] = $v->shop->address;
            }
            $_data['refund_status_cn'] = '';
            $_data['refund_no'] = '';
            $_data['shop_address'] = $v->shop->address;
            $_data['order_no'] = $v->order_no;
            $_data['serial_number'] = $v['serial_num'];
            $_data['is_group_buy'] = boolval($v['order_type'] == 6);
            $_data['pay_type'] = OrderModel::$posTypesZh[$v['pay_type']];
            $_data['pos_status_cn'] = OrderModel::$posTypesZh[$v['pos_type']];
            $_data['appointment_time'] = $v['appointment_time'];
            $result[] = $_data;
        }
        return $this->success($result, $list->total());
    }

    /**
     * 获取申请售后列表
     *
     * @param array $where
     * @param int $limit
     * @return array
     * @author mengchenchen
     */
    public function getRefundList($where = [], $limit = 10)
    {
        $result = [];
        $refund = OrderRefundModel::where($where)->orderBy('create_at', 'desc')->paginate($limit);
        foreach ($refund as $v) {
            if (!$order = OrderModel::where('order_no', $v->order_no)->first()) {
                continue;
            }
            $_data['create_at'] = $v->create_at;
            $_data['delivery_method'] = $order['deal_type'];
            $_data['delivery_method_cn'] = OrderModel::$deliveryMethodZh[$order['deal_type']];
            $_data['status'] = $order->status;
            $_data['deal_type'] = $order->deal_type;
            if ($order['deal_type'] == 1) {
                $_data['username'] = $order->address->username;
                $_data['phone'] = $order->address->phone;
                $_data['city'] = $order->address->city;
                $_data['area'] = $order->address->area;
                $_data['address'] = $order->address->address;
            } else {
                $_data['username'] = $order->member ? $order->member->nickname : '';
                $_data['phone'] = $order->member ? $order->member->phone : '';
                $_data['city'] = '';
                $_data['area'] = '';
                $_data['address'] = $order->shop->address;
            }
            $_data['status_name'] = $this->refund_status_name[$v->status];
            $_data['refund_status_cn'] = OrderModel::$handleStatusZh[$v->handle_type];
            $_data['refund_no'] = $v->refund_no;
            $_data['shop_address'] = $order->shop->address;
            $_data['order_no'] = $order->order_no;
            $_data['serial_number'] = $order['serial_num'];
            $_data['is_group_buy'] = boolval($order['order_type'] == 6);
            $_data['pay_type'] = OrderModel::$posTypesZh[$order['pay_type']];
            $_data['pos_status_cn'] = OrderModel::$posTypesZh[$order['pos_type']];
            $_data['appointment_time'] = $order['appointment_time'];
            $result[] = $_data;
        }
        return $this->success($result, $refund->total());
    }

    /**
     * 售后单订单号列表
     *
     * @param array $where
     * @return array
     */
    public function refundOrderNos($where = [])
    {
        $refund_nos = OrderRefundModel::query()->where($where)->select('order_no')->get();
        return $refund_nos ? $refund_nos->toArray() : [];
    }

    /**
     * 搜索订单条件
     *
     * @param $shop_id
     * @param $content
     * @return array
     */
    public function searchWhere($shop_id, $content)
    {
        if (preg_match("/1[23456789]\d{9}$/", $content)) {
            $member = $this->memberService->findFirst([['phone', 'like', "%$content%"]], ['mid']);
            if (!$member) {
                return ['order_no' => null];
            }
            $where = ['shop_id' => $shop_id, 'mid' => $member['mid']];
        } else {
            $where = ['shop_id' => $shop_id, 'order_no' => $content];
        }
        return $where;
    }

    /**
     * 详情页
     *
     * @param $where
     * @param string $refund_no
     * @return array
     */
    public function detail($where, $refund_no = '')
    {
        if ($order = $this->orderRepository->findFirst($where)) {
            $refund = new stdClass();
            $filed = 'CONCAT(goods_id,":",group_id) as only_key,goods_id,group_id,goods_title,number,dis_price';
            $goods_list = $order->goods()->selectRaw($filed)->get()->keyBy('only_key')->toArray();
            $statusName = OrderModel::$deliveryOrderStatusNamesZh[$order['status']];
            if ($order['deal_type'] == 2) {
                $statusName = OrderModel::$selfTakeOrderStatusNameZh[$order['status']];
            }
            if ($refund_no) {
                $_refund = OrderRefundModel::query()->where('refund_no', $refund_no)->first();
                $statusName = $this->refund_status_name[$_refund->status];
                $filed = 'CONCAT(goods_id,":",group_id) as only_key,order_no,goods_id,refund_number';
                $refund_goods = $_refund->goods()->select($filed)->get()->keyBy('only_key')->toArray();
                foreach ($goods_list as $k => $v) {
                    $goods_list[$k]['refund_number'] = $refund_goods[$k]['refund_number'] ?? 0;
                }
                $refund->handle_status = $_refund['handle_type'];
                $refund->handle_status_cn = OrderModel::$handleStatusZh[$_refund['handle_type']];
                $refund->is_whole = $_refund['is_whole'];
                $refund->apply_money = round($_refund['refund_money'], 2);
                $kz_refund = KzRefundLogModel::where('order_no', $order->order_no)->sum('refund_balance_money');
                $wx_refund = WxRefundLogModel::where('order_no', $order->order_no)->sum('refund_wx_money');
                $refund->actual_money = round(($kz_refund + $wx_refund), 2);
            }
            $data = [
                'created_at'      => $order['create_at'],
                'status_cn'       => $statusName,
                'delivery_method' => OrderModel::$deliveryMethodZh[$order['deal_type']],
                'member'          => [
                    'name'    => $order['deal_type'] == 1 ? $order->address->username : $order->member->nickname,
                    'phone'   => $order['deal_type'] == 1 ? $order->address->phone : $order->member->phone,
                    'address' => $order['deal_type'] == 1 ? $order->address->address : $order->shop->address,
                ],
                'order_no'        => $order['order_no'],
                'refund_no'       => $refund_no,
                'serial_number'   => $order['serial_num'],
                'pos_status_cn'   => OrderModel::$posTypesZh[$order['pos_type']],
                'want_take_time'  => $order['appointment_time'],
                'complete_date'   => $order['complete_date'],
                'goods_price'     => $order['goods_price'],
                'delivery_fee'    => $order['freight_price'],
                'coupon_amount'   => $order['coupon_cut'],
                'pay_type'        => OrderModel::$payTypesZh[$order['pay_type']],
                'payment_amount'  => $order['total_price'],
                'goods_list'      => array_values($goods_list),
                'refund'          => $refund,
            ];
            return $this->success($data);
        }
        return $this->error(ErrorCode::NOT_EXIST);
    }

    /**
     * 订单详情（需要单独定制的数据字段）
     *
     * @param $shop_id
     * @param $where
     * @param string $refund_no
     * @return array
     */
    public function shopOrderInfo($shop_id, $where, $refund_no = '')
    {
        if (!$order = $this->orderRepository->findFirst($where)) {
            return $this->error(ErrorCode::NOT_EXIST);
        }
        if ($order->shop_id != $shop_id) {
            return $this->error(403, '权限不足');
        }
        $refundObj = $refund_no ? OrderRefundModel::query()->where('refund_no', $refund_no)->first() : null;
        $statusName = $refundObj ? $this->refund_status_name[$refundObj->status]: OrderModel::$deliveryOrderStatusNamesZh[$order['status']];
        if ($order['deal_type'] == 2) {
            $statusName = OrderModel::$selfTakeOrderStatusNameZh[$order['status']];
        }
        $data = [
            'created_at'      => $order['create_at'],
            'status_cn'       => $statusName,
            'delivery_method' => OrderModel::$deliveryMethodZh[$order['deal_type']],
            'member'          => [
                'name'    => $order['deal_type'] == 1 ? $order->address->username : $order->member->nickname,
                'phone'   => $order['deal_type'] == 1 ? $order->address->phone : $order->member->phone,
                'address' => $order['deal_type'] == 1 ? $order->address->address : $order->shop->address,
            ],
            'order_no'        => $order['order_no'],
            'refund_no'        => $refund_no,
            'serial_number'   => $order['serial_num'],
            'pos_status_cn'   => OrderModel::$posTypesZh[$order['pos_type']],
            'want_take_time'  => $order['appointment_time'],
            'complete_date'   => $order['complete_date'],
            // 费用
            'goods_price'     => $order['goods_price'],
            'delivery_fee'    => $order['freight_price'],
            'coupon_amount'   => $order['coupon_cut'],
            'pay_type'        => OrderModel::$payTypesZh[$order['pay_type']],
            'payment_amount'  => $order['total_price'],
        ];
        // 商品列表
        $goods_list = $order->goods()->select([
            Db::raw('CONCAT(goods_id,":",group_id) as only_key'),
            'goods_id',
            'group_id',
            'goods_title',
            'number',
            'dis_price',
        ])->get()->keyBy('only_key')->toArray();
        $refund_actual_money = 0;
        // 退款信息
        $refund = new stdClass();
        if ($refund_no) {
//            $refund_no = OrderRefundModel::query()
//                ->where('order_no', $order->order_no)
//                ->orderBy('create_at', 'desc')
//                ->value('refund_no');
            $refund_goods = RefundGoodsModel::query()->where('refund_no', $refund_no)->get([
                Db::raw('CONCAT(goods_id,":",group_id) as only_key'),
                'order_no',
                'goods_id',
                'refund_number',
            ])->keyBy('only_key')->toArray();
            foreach ($goods_list as $k => $v) {
                $goods_list[$k]['refund_number'] = $refund_goods[$k]['refund_number'] ?? 0;
            }
            $kz_refund = KzRefundLogModel::query()
                ->where('order_no', $order->order_no)
                ->sum(Db::raw('refund_balance_money * 100'));
            $kz_refund && $refund_actual_money = $refund_actual_money + $kz_refund;
            $wx_refund = WxRefundLogModel::query()
                ->where('order_no', $order->order_no)
                ->sum(Db::raw('refund_wx_money * 100'));
            $wx_refund && $refund_actual_money = $refund_actual_money + $wx_refund;
            if ($_refund = OrderRefundModel::query()->where('refund_no', $refund_no)->first()) {
                $refund->handle_status = $_refund['handle_type'];
                $refund->handle_status_cn = OrderModel::$handleStatusZh[$_refund['handle_type']];
                $refund->is_whole = $_refund['is_whole'];
                $refund->apply_money = round($_refund['refund_money'], 2);
            }
            if ($refund_actual_money > 0) {
                // 处理状态中文
                $refund->actual_money = round(($kz_refund + $wx_refund) / 100, 2);
                $refund->handle_status = 2;
                $refund->handle_status_cn = OrderModel::$handleStatusZh[2];
                $refund->is_whole = $refund->actual_money == $order['total_price'] ? 0 : 1;
            }
        }
        $data['goods_list'] = array_values($goods_list);
        $data['refund'] = $refund;
        return $this->success($data);
    }

    /**
     * 发货
     *
     * Author: mengchenchen
     * Created_at: 2021/1/6 0006 11:52
     * Updated_at: 2021/1/6 0006 11:52
     *
     * @param $order_no
     * @return array
     */
    public function ship($order_no)
    {
        $order = $this->orderRepository->findFirst(['order_no' => $order_no]);
        if ($order) {
            $updateData['status'] = 3;
            $order['order_type'] == 6 && $updateData['order_type_status'] = 2;
            $ret = $this->orderRepository->update(['order_no' => $order_no], $updateData);
            if ($ret) {
                return $this->success();
            }
        }
        return $this->error(ErrorCode::NOT_IN_FORCE, '操作未生效');
    }

    /**
     * 批量发货
     *
     * @param array $order_nos
     * @return array
     */
    public function bulkShipping(array $order_nos)
    {
        $updateArr = [];
        $orders = OrderModel::query()->whereIn('order_no', $order_nos)->get(['order_no', 'order_type']);
        foreach ($orders as $order) {
            $_update['order_no'] = $order->order_no;
            $_update['status'] = 3;
            if ($order->order_type == 6) {
                $_update['order_type_status'] = 2;
            }
            $updateArr[] = $_update;
        }
        $ret = $this->updateBatch('store_order', $updateArr);
        if (!$ret) {
            return $this->error(ErrorCode::NOT_IN_FORCE);
        }
        return $this->success();
    }

    /**
     * 订单核销
     *
     * @param $shop_id
     * @param $write_off_code
     * @return array
     */
    public function writeOff($shop_id, $write_off_code)
    {
        try {
            $order = OrderModel::query()->where('write_off_code', $write_off_code)->first();
            if (!$order) {
                throw new Exception('不存在', ErrorCode::NOT_EXIST);
            }
            if ($order->shop_id != $shop_id) {
                throw new Exception('权限不足', 403);
            }
            if ($order->write_off_code_status == 2) {
                throw new Exception('请勿重复核销', ErrorCode::NOT_IN_FORCE);
            }
            if (date('Ymd', strtotime($order['appointment_date'])) > date('Ymd')) {
                throw new Exception('不能提前核销', ErrorCode::NOT_IN_FORCE);
            }
            $res = $order->update(['write_off_code_status' => 2, 'status' => 4]);
            if (!$res) {
                throw new Exception('核销失败', ErrorCode::NOT_IN_FORCE);
            }
            return $this->success();
        } catch (Exception $e) {
            return $this->error($e->getCode(), $e->getMessage());
        }
    }

    /**
     * 确认送达
     *
     * Author: mengchenchen
     * Created_at: 2021/1/6 0006 13:51
     * Updated_at: 2021/1/6 0006 13:51
     *
     * @param $order_no
     * @return array
     */
    public function arrival($order_no)
    {
        $ret = $this->orderRepository->update(['order_no' => $order_no], [
            'status'        => 4,
            'complete_date' => date('Y-m-d H:i:s'),
        ]);
        if (!$ret) {
            $this->error(ErrorCode::NOT_IN_FORCE);
        }
        return $this->success();
    }

    /**
     * 拒绝退款
     *
     * @param $order_no
     * @return array
     */
    public function refuseRefund($order_no)
    {
        try {
            $info = $this->orderRepository->findFirst(['order_no' => $order_no]);
            if (!$info) {
                throw new Exception('找不到此订单', ErrorCode::NOT_EXIST);
            }
            if ($info->status != 7) {
                throw new Exception('当前订单未申请售后', ErrorCode::NOT_EXIST);
            }
            $refund = OrderRefundModel::query()->where('order_no', $order_no)->first([
                'refund_no',
                'order_no',
                'before_status',
            ]);
            if (!$refund) {
                throw new Exception('不存在的退款订单', ErrorCode::NOT_EXIST);
            }
            $goods = RefundGoodsModel::query()->where('refund_no', $refund->refund_no)->get([
                'id',
                'goods_id',
                'refund_number',
            ])->keyBy('goods_id');
            $orderGoods = OrderGoodsModel::query()->where('order_no', $order_no)->get([
                    'id',
                    'refund_number',
                    'goods_id',
                ])->keyBy('goods_id');
            foreach ($orderGoods as $k => $v) {
                if ($v['refund_number'] > 0) {
                    $v['refund_number'] -= $goods[$k]['refund_number'] ?? 0;
                    $v->save();
                }
            }
            $res1 = OrderRefundModel::query()->where('order_no', $order_no)->update([
                'status'      => 1,
                'handle_type' => 2,
                'refund_at'   => date('Y-m-d H:i:s', time()),
            ]);
            if (!$res1) {
                throw new Exception('保存退款表失败', ErrorCode::NOT_IN_FORCE);
            }
            $res2 = $info->update(['status' => $refund['before_status']]);
            if (!$res2) {
                throw new Exception('更改订单状态失败', ErrorCode::NOT_IN_FORCE);
            }
        } catch (Exception $e) {
            return $this->error($e->getCode(), $e->getMessage());
        }
        return $this->success();
    }

    /**
     * 获取订单数量
     *
     * @param $shop_id
     * @return array
     */
    public function getOrderCount($shop_id)
    {
        $func = function ($where) use ($shop_id) {
            return OrderModel::query()->whereRaw($where)->where('shop_id', $shop_id)->count();
        };
        // 待发货
        $waiting_ship = $func('status = 2 and order_type_status <> 2');
        // 配送中
        $in_delivery = $func('status = 3 and order_type_status <> 2 and deal_type = 1');
        // 待自提
        $waiting_take = $func('status = 3 and order_type_status <> 1 and deal_type = 2');
        // 用户售后申请退款单
        $refund = $func('status = 7');
        return $this->success(compact('waiting_ship', 'in_delivery', 'waiting_take', 'refund'));
    }

    /**
     * 商家主动退页面
     *
     * Author: mengchenchen
     * Created_at: 2021/1/6 0006 11:57
     * Updated_at: 2021/1/6 0006 11:57
     *
     * @param $order_no
     * @return array
     */
    public function getDrivingRefundInfo($order_no)
    {
        $order = $this->orderRepository->findFirst(['order_no' => $order_no]);
        if (!$order) {
            return $this->error(ErrorCode::NOT_EXIST);
        }
        $field = [
            'id',
            'goods_id',
            'goods_title',
            'goods_spec',
            'goods_logo',
            Db::raw('number - IF(status = 1,refund_number+shop_refund_number,0) as number'),
            'selling_price',
            'goods_dis_price',
            'deductMoney',
            'kz_self_num',
        ];
        $goodsList = $order->goods()->select($field)->having('number', '>', 0)->get();
        return $this->success($goodsList);
    }

}
